﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.CampaignSystem.Settlements.Locations.Location
// Assembly: TaleWorlds.CampaignSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E85F8C15-4DF6-4E9C-A58A-29177E40D07A
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\bin\Win64_Shipping_Client\TaleWorlds.CampaignSystem.dll

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.Localization;
using TaleWorlds.SaveSystem;

#nullable disable
namespace TaleWorlds.CampaignSystem.Settlements.Locations
{
  public class Location
  {
    [SaveableField(40)]
    private TextObject _overriddenName;
    [SaveableField(50)]
    private TextObject _overriddenDoorName;
    private List<LocationCharacter> _characterList;
    private LocationComplex _ownerComplex;
    private TextObject _name;
    private TextObject _doorName;
    public int ProsperityMax;
    private string[] _sceneNames;
    private string _aiCanExit;
    private string _aiCanEnter;
    private string _playerCanEnter;
    private string _playerCanSee;
    private CanUseDoor _aiCanExitDelegate;
    private CanUseDoor _aiCanEnterDelegate;
    private CanUseDoor _playerCanEnterDelegate;
    private CanUseDoor _playerCanSeeDelegate;

    internal static void AutoGeneratedStaticCollectObjectsLocation(
      object o,
      List<object> collectedObjects)
    {
      ((Location) o).AutoGeneratedInstanceCollectObjects(collectedObjects);
    }

    protected virtual void AutoGeneratedInstanceCollectObjects(List<object> collectedObjects)
    {
      collectedObjects.Add((object) this._overriddenName);
      collectedObjects.Add((object) this._overriddenDoorName);
      collectedObjects.Add((object) this.SpecialItems);
    }

    internal static object AutoGeneratedGetMemberValueStringId(object o)
    {
      return (object) ((Location) o).StringId;
    }

    internal static object AutoGeneratedGetMemberValueSpecialItems(object o)
    {
      return (object) ((Location) o).SpecialItems;
    }

    internal static object AutoGeneratedGetMemberValueIsReserved(object o)
    {
      return (object) ((Location) o).IsReserved;
    }

    internal static object AutoGeneratedGetMemberValue_overriddenName(object o)
    {
      return (object) ((Location) o)._overriddenName;
    }

    internal static object AutoGeneratedGetMemberValue_overriddenDoorName(object o)
    {
      return (object) ((Location) o)._overriddenDoorName;
    }

    [SaveableProperty(10)]
    public string StringId { get; private set; }

    [SaveableProperty(20)]
    public List<ItemObject> SpecialItems { get; private set; }

    [SaveableProperty(30)]
    public bool IsReserved { get; private set; }

    public List<Location> LocationsOfPassages { get; private set; }

    public TextObject Name
    {
      get => !TextObject.IsNullOrEmpty(this._overriddenName) ? this._overriddenName : this._name;
    }

    public TextObject DoorName
    {
      get
      {
        return !this._overriddenDoorName.Equals(TextObject.Empty) ? this._overriddenDoorName : this._doorName;
      }
    }

    public bool IsIndoor { get; private set; }

    public bool CanBeReserved { get; private set; }

    [CachedData]
    public bool IsInitialized { get; private set; }

    public int CharacterCount => this._characterList.Count;

    public Location(
      string stringId,
      TextObject name,
      TextObject doorName,
      int prosperityMax,
      bool isIndoor,
      bool canBeReserved,
      string playerCanEnter,
      string playerCanSee,
      string aiCanExit,
      string aiCanEnter,
      string[] sceneNames,
      LocationComplex locationComplex)
    {
      this.ProsperityMax = prosperityMax;
      this._characterList = new List<LocationCharacter>();
      this.LocationsOfPassages = new List<Location>();
      this.SpecialItems = new List<ItemObject>();
      this.StringId = stringId;
      this._name = name;
      this._doorName = doorName;
      this.IsIndoor = isIndoor;
      this.CanBeReserved = canBeReserved;
      this.IsReserved = false;
      this._aiCanEnter = aiCanEnter;
      this._playerCanEnter = playerCanEnter;
      this._playerCanSee = playerCanSee;
      this._aiCanExit = aiCanExit;
      this._ownerComplex = locationComplex;
      this._overriddenName = TextObject.Empty;
      this._overriddenDoorName = TextObject.Empty;
      this._sceneNames = new string[4];
      for (int index = 0; index < 4; ++index)
        this._sceneNames[index] = sceneNames[index];
    }

    public Location(Location location, LocationComplex locationComplex)
      : this(location.StringId, location.Name, location.DoorName, location.ProsperityMax, location.IsIndoor, location.CanBeReserved, location._playerCanEnter, location._playerCanSee, location._aiCanExit, location._aiCanEnter, location._sceneNames, locationComplex)
    {
    }

    public void Initialize(Location locationTemplate, LocationComplex ownerComplex)
    {
      this.ProsperityMax = locationTemplate.ProsperityMax;
      this.LocationsOfPassages = new List<Location>();
      this._name = locationTemplate.Name;
      this._doorName = locationTemplate.DoorName;
      this.IsIndoor = locationTemplate.IsIndoor;
      this.CanBeReserved = locationTemplate.CanBeReserved;
      this._aiCanEnter = locationTemplate._aiCanEnter;
      this._playerCanEnter = locationTemplate._playerCanEnter;
      this._playerCanSee = locationTemplate._playerCanSee;
      this._aiCanExit = locationTemplate._aiCanExit;
      this._ownerComplex = ownerComplex;
      this._characterList = new List<LocationCharacter>();
      this._sceneNames = new string[4];
      this.IsInitialized = true;
      for (int index = 0; index < 4; ++index)
        this._sceneNames[index] = locationTemplate._sceneNames[index];
    }

    public bool CanAIExit(LocationCharacter character)
    {
      if (this._aiCanExitDelegate == null)
        this._aiCanExitDelegate = this.DeserializeDelegate(this._aiCanExit);
      return this._aiCanExitDelegate(character, this);
    }

    public bool CanAIEnter(LocationCharacter character)
    {
      if (this._aiCanEnterDelegate == null)
        this._aiCanEnterDelegate = this.DeserializeDelegate(this._aiCanEnter);
      return this._aiCanEnterDelegate(character, this);
    }

    public bool CanPlayerEnter()
    {
      if (this._playerCanEnterDelegate == null)
        this._playerCanEnterDelegate = this.DeserializeDelegate(this._playerCanEnter);
      return this._playerCanEnterDelegate((LocationCharacter) null, this);
    }

    public bool CanPlayerSee()
    {
      if (this._playerCanSeeDelegate == null)
        this._playerCanSeeDelegate = this.DeserializeDelegate(this._playerCanSee);
      return this._playerCanSeeDelegate((LocationCharacter) null, this);
    }

    public void ReserveLocation(TextObject locationName, TextObject doorName)
    {
      if (!this.CanBeReserved)
        return;
      this.IsReserved = true;
      this._overriddenName = locationName;
      this._overriddenDoorName = doorName;
    }

    public void RemoveReservation()
    {
      if (!this.CanBeReserved)
        return;
      this.IsReserved = false;
      this._overriddenName = TextObject.Empty;
      this._overriddenDoorName = TextObject.Empty;
    }

    public void SetOwnerComplex(LocationComplex locationComplex)
    {
      this._ownerComplex = locationComplex;
    }

    public void AddCharacter(LocationCharacter locationCharacter)
    {
      if (this._characterList == null)
        this._characterList = new List<LocationCharacter>();
      if (locationCharacter.Character.IsHero)
        this._ownerComplex.RemoveCharacterIfExists(locationCharacter.Character.HeroObject);
      this._characterList.Add(locationCharacter);
    }

    public void AddLocationCharacters(
      CreateLocationCharacterDelegate createDelegate,
      CultureObject culture,
      LocationCharacter.CharacterRelations relation,
      int count)
    {
      for (int index = 0; index < count; ++index)
        this.AddCharacter(createDelegate(culture, relation));
    }

    public void AddSpecialItem(ItemObject itemObject) => this.SpecialItems.Add(itemObject);

    public string GetSceneName(int upgradeLevel)
    {
      string sceneName = this._sceneNames[upgradeLevel];
      if (string.IsNullOrEmpty(sceneName))
        sceneName = this._sceneNames[0];
      return sceneName;
    }

    public void SetSceneName(int upgradeLevel, string sceneName)
    {
      this._sceneNames[upgradeLevel] = sceneName;
    }

    public int GetSceneCount()
    {
      int sceneCount = 0;
      foreach (string sceneName in this._sceneNames)
      {
        if (!string.IsNullOrEmpty(sceneName))
          ++sceneCount;
      }
      return sceneCount;
    }

    public void RemoveAllHeroCharactersFromPrison()
    {
      if (this._characterList == null)
        this._characterList = new List<LocationCharacter>();
      this._characterList.RemoveAll((Predicate<LocationCharacter>) (x => x.Character.HeroObject != null && x.Character.HeroObject != Hero.MainHero));
    }

    public void RemoveAllCharacters()
    {
      if (this._characterList == null)
        this._characterList = new List<LocationCharacter>();
      this._characterList.Clear();
    }

    public void RemoveAllCharacters(Predicate<LocationCharacter> predicate)
    {
      this._characterList.RemoveAll(predicate);
    }

    public void RemoveLocationCharacter(LocationCharacter locationCharacter)
    {
      this._characterList.Remove(locationCharacter);
    }

    public void RemoveCharacter(Hero hero)
    {
      this.RemoveLocationCharacter(this._characterList.First<LocationCharacter>((Func<LocationCharacter, bool>) (x => x.Character.HeroObject == hero)));
    }

    public bool ContainsCharacter(LocationCharacter locationCharacter)
    {
      return this._characterList.Contains(locationCharacter);
    }

    public bool ContainsCharacter(Hero hero)
    {
      return this._characterList != null && this._characterList.Any<LocationCharacter>((Func<LocationCharacter, bool>) (x => x.Character == hero.CharacterObject));
    }

    public void AddPassageToLocation(Location passageToLocation)
    {
      this.LocationsOfPassages.Add(passageToLocation);
    }

    public IEnumerable<LocationCharacter> GetCharacterList()
    {
      if (this._characterList == null)
        this._characterList = new List<LocationCharacter>();
      foreach (LocationCharacter character in this._characterList)
        yield return character;
    }

    public Location GetPassageToLocation(string locationId)
    {
      return this.LocationsOfPassages.FirstOrDefault<Location>((Func<Location, bool>) (location => locationId == location.StringId));
    }

    public void OnAIChangeLocation(Location previousLocation)
    {
      if (!this.IsIndoor || CampaignMission.Current == null || this == CampaignMission.Current.Location || CampaignMission.Current.Mode != MissionMode.Stealth)
        return;
      this._playerCanEnterDelegate = new CanUseDoor(LocationComplex.CanNever);
    }

    public LocationCharacter GetLocationCharacter(Hero hero)
    {
      return this._characterList.Find((Predicate<LocationCharacter>) (x => x.Character == hero.CharacterObject));
    }

    public LocationCharacter GetLocationCharacter(IAgentOriginBase agentOrigin)
    {
      foreach (LocationCharacter character in this._characterList)
      {
        if (character.AgentOrigin == agentOrigin)
          return character;
      }
      return (LocationCharacter) null;
    }

    private CanUseDoor DeserializeDelegate(string text)
    {
      int length = text.LastIndexOf('.');
      string name1 = length >= 0 ? text.Substring(0, length) : typeof (LocationComplex).FullName;
      string name2 = text.Substring(length + 1, text.Length - 1 - length);
      CanUseDoor canUseDoor = (CanUseDoor) null;
      foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
      {
        Type type = assembly.GetType(name1);
        if (type != (Type) null)
        {
          MethodInfo method = type.GetMethod(name2);
          if (method != (MethodInfo) null)
          {
            canUseDoor = Delegate.CreateDelegate(typeof (CanUseDoor), (object) null, method) as CanUseDoor;
            break;
          }
        }
      }
      return canUseDoor;
    }
  }
}
